// bslstl_stringview.h                                                -*-C++-*-
#ifndef INCLUDED_BSLSTL_STRINGVIEW
#define INCLUDED_BSLSTL_STRINGVIEW

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a standard-compliant `basic_string_view` class template.
//
//@CLASSES:
//  bsl::basic_string_view: C++ compliant `basic_string_view` implementation
//  bsl::string_view: `typedef` for `bsl::basic_string_view<char>`
//  bsl::wstring_view: `typedef` for `bsl::basic_string_view<wchar_t>`
//
//@CANONICAL_HEADER: bsl_string_view.h
//
//@SEE_ALSO: ISO C++ Standard, bdlb_stringviewutil
//
//@DESCRIPTION: This component defines a single class template
// `bsl::basic_string_view` and aliases for ordinary and wide character
// specializations `bsl::string_view` and `bsl::wstring_view` implementing
// standard containers, `std::string_view` and `std::wstring_view`, that can
// refer to a constant contiguous sequence of char-like objects with the first
// element of the sequence at position zero.
//
// An instantiation of `basic_string_view` is a value-semantic type whose
// salient attribute is the sequence of characters it represents.  The
// `basic_string_view` `class` is parameterized by the character type,
// `CHAR_TYPE` and that character type's traits, `CHAR_TRAITS`.  The traits for
// each character type provide functions that assign, compare, and copy a
// sequence of those characters.
//
// A `basic_string_view` meets the requirements of a sequential container with
// random access iterators as specified in the [basic.string_view] section of
// the C++ standard [24.4].  The `basic_string_view` implemented here adheres
// to the C++17 standard, except that it does not have template specializations
// `std::u16string_view` and `std::u32string_view`.  Note that if compiler
// supports C++17 standard, then `stl` implementation of `basic_string_view` is
// used.
//
///Lexicographical Comparisons
///---------------------------
// Two `basic_string_view`s `lhs` and `rhs` are lexicographically compared by
// first determining `N`, the smaller of the lengths of `lhs` and `rhs`, and
// comparing characters at each position between 0 and `N - 1`, using
// `CHAR_TRAITS::compare` in lexicographical fashion.  If
// `CHAR_TRAITS::compare` determines that string_views are non-equal (smaller
// or larger), then this is the result.  Otherwise, the lengths of the
// string_views are compared and the shorter string_view is declared the
// smaller.  Lexicographical comparison returns equality only when both
// string_views have the same length and the same character value in each
// respective position.
//
///Operations
///----------
// This section describes the run-time complexity of operations on instances of
// `basic_string_view`:
// ```
// Legend
// ------
// 'V'              - the 'CHAR_TYPE' template parameter type of the
//                    'basic_string_view'
// 'a', 'b'         - two distinct objects of type 'basic_string_view<V>'
// 'k'              - an integral number
// 'p'              - a pointer defining a sequence of 'CHAR_TYPE' characters
//
// +----------------------------------------------+--------------------------+
// | Operation                                    | Complexity               |
// |==============================================+==========================|
// | basic_string_view<V> a (default construction)| O[1]                     |
// |----------------------------------------------+--------------------------|
// | basic_string_view<V> a(b) (copy construction)| O[1]                     |
// |----------------------------------------------+--------------------------|
// | basic_string_view<V> a(p)                    | O[n]                     |
// |----------------------------------------------+--------------------------|
// | basic_string_view<V> a(p, k)                 | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.~basic_string_view<V>() (destruction)      | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.begin(), a.end(),                          | O[1]                     |
// | a.cbegin(), a.cend(),                        |                          |
// | a.rbegin(), a.rend(),                        |                          |
// | a.crbegin(), a.crend()                       |                          |
// |----------------------------------------------+--------------------------|
// | a.size()                                     | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.max_size()                                 | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.remove_prefix(k)                           | O[1]                     |
// | a.remove_suffix(k)                           |                          |
// |----------------------------------------------+--------------------------|
// | a[k]                                         | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.at(k)                                      | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.front()                                    | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.back()                                     | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a.swap(b), swap(a, b)                        | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a = b; (assignment)                          | O[1]                     |
// |----------------------------------------------+--------------------------|
// | a == b, a != b                               | O[n]                     |
// |----------------------------------------------+--------------------------|
// | a < b, a <= b, a > b, a >= b                 | O[n]                     |
// +----------------------------------------------+--------------------------+
// ```
//
///User-defined literals
///---------------------
// The user-defined literal operators are declared for the `bsl::string_view`
// and `bsl::wstring_view` types.  The ud-suffix `_sv` is chosen to distinguish
// between the `bsl`-string_view's user-defined literal operators and the
// `std`-string_view's user-defined literal `operator ""sv` introduced in the
// C++14 standard and implemented in the standard library provided by the
// compiler vendor.  Note that the `bsl`-string_view's `operator""_sv`,
// unlike the `std`-string_view's `operator ""sv`, can be used in a client's
// code if the compiler supports the C++11 standard.  Also note that if the
// compiler supports the C++17 standard then the `std`-string_view's
// `operator ""sv` can be used to initialize a `bsl`-string_view as follows:
// ```
// using namespace std::string_view_literals;
// bsl::string_view sv = "test"sv;
// ```
//
// Also note that `bsl`-string_view's user-defined literal operators are
// declared in the `bsl::literals::string_view_literals` namespace, where
// `literals` and `string_view_literals` are inline namespaces.  Access to
// these operators can be gained with either `using namespace bsl::literals`,
// `using namespace bsl::string_view_literals` or
// `using namespace bsl::literals::string_view_literals`.  But we recommend
// `using namespace bsl::string_view_literals` to minimize the scope of the
// using declaration:
// ```
// using namespace bsl::string_view_literals;
// bsl::string_view svr = "test"_sv;
// ```
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Basic Syntax
///- - - - - - - - - - - -
// The `bsl::string_view` can be used as a lightweight replacement of the
// `bsl::string`, unless you need to modify the content.  It takes up no more
// space and doesn't allocate memory:
// ```
//     bslma::TestAllocator         da("Default", veryVeryVeryVerbose);
//     bslma::DefaultAllocatorGuard dag(&da);
//
//     bslma::TestAllocator sfa ("StringFootprint",     veryVeryVeryVerbose);
//     bslma::TestAllocator svfa("StringViewFootprint", veryVeryVeryVerbose);
//     bslma::TestAllocator ssa ("StringSupplied",      veryVeryVeryVerbose);
//
//     const char *LONG_STRING = "0123456789012345678901234567890123456789"
//                               "0123456789012345678901234567890123456789";
//
//     bsl::string      *sPtr  = new (sfa ) bsl::string(LONG_STRING, &ssa);
//     bsl::string_view *svPtr = new (svfa) bsl::string_view(LONG_STRING);
//
//     assert(sfa.numBytesInUse() >= svfa.numBytesInUse());
//     assert(0                   <   ssa.numBytesInUse());
//     assert(0                   ==   da.numBytesInUse());
// ```
// At the same time it supports all most used `access` operations of the
// `bsl::string`, using the same interfaces:
// ```
//     const bsl::string&      STR = *sPtr;
//     const bsl::string_view& SV  = *svPtr;
//
//     assert(STR.length()                == SV.length());
//     assert(STR.empty()                 == SV.empty());
//     assert(STR.front()                 == SV.front());
//     assert(STR.at(15)                  == SV.at(15));
//     assert(STR.find("345")             == SV.find("345"));
//     assert(STR.find_last_not_of("578") == SV.find_last_not_of("578"));
//     assert(STR.compare(0, 3, "012")    == SV.compare(0, 3, "012"));
// ```
// However, using the `bsl::string_view`, you need to be especially attentive
// to the lifetime of the source character string, since the component
// explicitly refers to it:
// ```
//     assert(LONG_STRING != STR.data());
//     assert(LONG_STRING == SV.data());
//
//     sfa.deleteObject(sPtr);
//     svfa.deleteObject(svPtr);
// ```

#include <bslscm_version.h>

#include <bslstl_hash.h>
#include <bslstl_iterator.h>
#include <bslstl_stdexceptutil.h>

#include <bslalg_scalarprimitives.h>

#include <bslh_hash.h>

#include <bslmf_addconst.h>
#include <bslmf_addpointer.h>
#include <bslmf_enableif.h>
#include <bslmf_isconvertible.h>
#include <bslmf_istriviallycopyable.h>
#include <bslmf_nestedtraitdeclaration.h>
#include <bslmf_switch.h>

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_libraryfeatures.h>
#include <bsls_performancehint.h>
#include <bsls_platform.h>

#include <cstddef>     // for 'std::size_t'
#include <functional>  // for 'std::less', 'std::greater_equal'
#include <string>      // for 'std::char_traits'

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
# include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

#if  defined(BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY)     \
&&  (!defined(BSLS_LIBRARYFEATURES_HAS_CPP20_BASELINE_LIBRARY) || \
     (defined(BSLS_LIBRARYFEATURES_FORCE_ABI_ENABLED) &&          \
     (BSLS_LIBRARYFEATURES_FORCE_ABI_ENABLED < 20)))
    /// `bsl` and `std::string_view`s coexist when we have at least C++17
    /// standard library available, but C++20 library is not available, or it
    /// is disabled due to ABI compatibility reasons.
# define BSLSTL_STRING_VIEW_AND_STD_STRING_VIEW_COEXIST
#endif

#if defined (BSLS_LIBRARYFEATURES_HAS_CPP20_BASELINE_LIBRARY) && \
   !(defined(BSLS_LIBRARYFEATURES_FORCE_ABI_ENABLED) &&          \
    (BSLS_LIBRARYFEATURES_FORCE_ABI_ENABLED < 20))

    /// `BSLSTL_STRING_VIEW_IS_ALIASED` is defined when `bsl::string_view` and
    /// its accompanying symbols are aliases to their `std` equivalents.  Note
    /// that `std::string` may coexist with `bsl::string_view` that is *not* an
    /// alias of it; see `BSLSTL_STRING_VIEW_AND_STD_STRING_VIEW_COEXIST`.
# define BSLSTL_STRING_VIEW_IS_ALIASED

# include <string_view>

    namespace bsl {

using std::basic_string_view;
using std::string_view;
using std::wstring_view;

# if defined(BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE)
using std::u8string_view;
# endif

using std::u16string_view;
using std::u32string_view;

using std::swap;

using std::operator==;
using std::operator!=;
using std::operator<;
using std::operator<=;
using std::operator>;
using std::operator>=;

}
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP20_BASELINE_LIBRARY & not disabled

#ifndef BSLSTL_STRING_VIEW_IS_ALIASED

#if defined(BSLS_PLATFORM_OS_WINDOWS) ||                                      \
   (defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION <  0x5130) || \
   (defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION == 0x5150)
  // Windows or Sun CC before version 5.12.4 or Sun CC version 5.12.6

# define BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER    1
#else
# define BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER    0
#endif

namespace BloombergLP {
namespace bslstl {

                         // ===========================
                         // struct 'StringView_Identity
                         // ===========================

template <class TYPE>
struct StringView_Identity {
#if BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER
    // See 'Implementation Notes' in the implementation .cpp file.

    // TYPES
    struct type {
        // DATA
        TYPE d_value;

        // CREATOR

        /// Initialize `d_value` from the specified `argument`, of the
        /// specified `ARG_TYPE`, where `ARG_TYPE` can be any type that is
        /// convertible to the specified `TYPE`.
        template <class ARG_TYPE>
        type(const ARG_TYPE& argument,
                     typename
                     bsl::enable_if<bsl::is_convertible<ARG_TYPE, TYPE>::value,
                                    int>::type = 0);

        //! type(const type&) = default;

        // MANIPULATORS

        //! type& operator=(const type&) = default;

        /// Assign the specified `rhs` of type `TYPE` to this object, and
        /// return a reference providing modifiable access to the `TYPE`
        /// object held by this object.
        TYPE& operator=(const TYPE& rhs);

        /// Return a reference providing modifiable access to the `TYPE`
        /// object held by this object.
        operator TYPE&();

        // ACCESSOR

        /// Return a const reference to the `TYPE` object held by this
        /// object.
        operator const TYPE&() const;
    };
#else
    // TYPES
    typedef TYPE type;
#endif
};

}  // close package namespace
}  // close enterprise namespace

namespace bsl {

            // ===========================================
            // struct BasicStringView_IsCompatibleIterator
            // ===========================================

/// `value` is 1 if (template parameter) type `CONTG_ITER` is convertible to
/// `const CHAR_TYPE *` (i.e., convertible to `d_start_p` of
/// `basic_string_view`); otherwise, `value` is 0.
template <class CHAR_TYPE, class CONTG_ITER>
struct BasicStringView_IsCompatibleIterator : bsl::is_convertible<
                                      CONTG_ITER,
                                      typename bsl::add_pointer<
                                      typename bsl::add_const<CHAR_TYPE>::type
                                                                       >::type>
{
};

            // ===========================================
            // struct BasicStringView_IsCompatibleSentinel
            // ===========================================

/// `value` is 1 if (template parameter) type `SENTINEL> is *not*
/// convertible to `size_type`, and 0 otherwise.
template <class SENTINEL>
struct BasicStringView_IsCompatibleSentinel :
    bsl::integral_constant<bool,
                           ! bsl::is_convertible<SENTINEL, std::size_t>::value>
{
};

// Import 'char_traits' into the 'bsl' namespace so that 'basic_string_view'
// and 'char_traits' are always in the same namespace.

using std::char_traits;

                        // =======================
                        // class basic_string_view
                        // =======================

/// This class template provides an STL-compliant `string_view`.  This
/// implementation offers strong exception guarantees (see below), with the
/// general rule that any method that attempts to access a position outside
/// the valid range of a string_view throws `std::out_of_range`.
///
/// Note that the search methods, such as `find`, `rfind`, etc, do *not*
/// actually access invalid positions, so they do *not* throw exceptions.
///
/// More generally, this class supports an almost complete set of *in-core*
/// *value* *semantic* operations, including copy construction, assignment,
/// equality comparison (but excluding `ostream` printing since this
/// component is below STL).  A precise operational definition of when two
/// objects have the same value can be found in the description of
/// `operator==` for the class.  This class is *exception* *neutral* with
/// full guarantee of rollback: if an exception is thrown during the
/// invocation of a method on a pre-existing object, the object is left
/// unchanged.  In no event is memory leaked.
template <class CHAR_TYPE, class CHAR_TRAITS = char_traits<CHAR_TYPE> >
class basic_string_view {

  public:
    // TYPES
    typedef CHAR_TRAITS                            traits_type;
    typedef CHAR_TYPE                              value_type;
    typedef value_type                            *pointer;
    typedef const value_type                      *const_pointer;
    typedef value_type&                            reference;
    typedef const value_type&                      const_reference;
    typedef const value_type                      *const_iterator;
    typedef const_iterator                         iterator;

    typedef bsl::reverse_iterator<iterator>        reverse_iterator;
    typedef bsl::reverse_iterator<const_iterator>  const_reverse_iterator;

    typedef std::size_t                            size_type;
    typedef std::ptrdiff_t                         difference_type;

  public:
    // CLASS DATA

    /// Value used to denote "not-a-position", guaranteed to be outside the
    /// range `[0 .. max_size()]`.
    static const size_type npos = ~size_type(0);

  private:
    // DATA
    const CHAR_TYPE *d_start_p;  // pointer to the data
    size_type        d_length;   // length of the view

    // PRIVATE ACCESSORS

    /// Lexicographically compare the substring of this string starting at
    /// the specified `lhsPosition` of length `lhsNumChars` with the
    /// specified initial `otherNumChars` characters in the specified
    /// `other` string, and return a negative value if the indicated
    /// substring of this string is less than `other`, a positive value if
    /// it is greater than `other`, and 0 in case of equality.  The behavior
    /// is undefined unless `lhsPosition <= length()`,
    /// `lhsNumChars <= length()`, and
    /// `lhsPosition <= length() - lhsNumChars`.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    int privateCompareRaw(size_type        lhsPosition,
                          size_type        lhsNumChars,
                          const CHAR_TYPE *other,
                          size_type        otherNumChars) const;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(basic_string_view,
                                   bsl::is_trivially_copyable);

    // CREATORS

    /// Create an empty view.
    BSLS_KEYWORD_CONSTEXPR
    basic_string_view() BSLS_KEYWORD_NOEXCEPT;

    /// Create a view that has the same value as the specified `original`
    /// object.
    //! basic_string_view(const basic_string_view& original) = default;

    /// Create a view of the specified null-terminated `characterString` (of
    /// length `CHAR_TRAITS::length(characterString)`).
    BSLS_KEYWORD_CONSTEXPR_CPP17
    basic_string_view(const CHAR_TYPE *characterString);           // IMPLICIT

    /// Create a view that has the same value as the subview of the
    /// optionally specified `numChars` length starting at the beginning of
    /// the specified `characterString`.  The behavior is undefined unless
    /// `characterString || (numChars == 0)` and `numChars <= max_size()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view(const CHAR_TYPE *characterString,
                      size_type        numChars);

    /// Create a view from of characters in the range starting at the
    /// specified `first`, a contiguous iterator, to the position
    /// immediately before the specified `end`, a sentinel type.  The
    /// behavior is undefined unless:
    /// * `[first, last)` is a contiguous valid range,
    /// *o if `first` is 0, then `0 == last - first`, and
    /// *o the `SENTINEL` type is *not* convertible to `std::size_t`.
    /// Note that contiguous iterator types also provide random access.
    /// Also note that pointers to `CHAR_TYPE` can be used as iterator and
    /// sentinel types.
    template <class CONTG_ITER, class SENTINEL>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view(CONTG_ITER first,
                      SENTINEL   last,
                      typename
                      bsl::enable_if<
                      BasicStringView_IsCompatibleIterator<CHAR_TYPE,
                                                           CONTG_ITER>::value
                   && BasicStringView_IsCompatibleSentinel<SENTINEL  >::value
                      >::type * = 0);

    /// Create a view of the specified `string`.
    template <class ALLOCATOR>
    basic_string_view(
              const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& str);
                                                                    // IMPLICIT

#ifdef BSLSTL_STRING_VIEW_AND_STD_STRING_VIEW_COEXIST
    /// Create a view identical to the specified `view`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view(
                   const std::basic_string_view<CHAR_TYPE, CHAR_TRAITS>& view);
                                                                    // IMPLICIT

#endif // BSLSTL_STRING_VIEW_AND_STD_STRING_VIEW_COEXIST

    /// Destroy this object.
    //! ~basic_string_view() = default;

    // MANIPULATORS

    /// Assign to this view the value of the specified `rhs` object, and
    /// return a reference providing modifiable access to this view.
    //! basic_string_view& operator=(const basic_string_view& rhs) = default;

    /// Assign to this view the value of the specified `rhs` object, and
    /// return a reference providing modifiable access to this view.
    template <class ALLOCATOR>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view& operator=(
               const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& rhs)
    BSLS_KEYWORD_NOEXCEPT;

    /// Move the start of this view forward by the specified `numChars`.
    /// The behavior is undefined unless `numChars <= length()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    void remove_prefix(size_type numChars);

    /// Move the end of this view back by the specified `numChars`.  The
    /// behavior is undefined unless `numChars <= length()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    void remove_suffix(size_type numChars);

    /// Exchange the value of this view with the value of the specified
    /// `other` object.
    void swap(basic_string_view& other) BSLS_KEYWORD_NOEXCEPT;

    // ACCESSORS

                      // *** iterator support ***

    /// Return an iterator providing non-modifiable access to the first
    /// character of this view (or the past-the-end iterator if this view is
    /// empty).
    BSLS_KEYWORD_CONSTEXPR
    const_iterator  begin() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR
    const_iterator cbegin() const BSLS_KEYWORD_NOEXCEPT;

    /// Return the past-the-end iterator for this view.
    BSLS_KEYWORD_CONSTEXPR
    const_iterator  end() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR
    const_iterator cend() const BSLS_KEYWORD_NOEXCEPT;

    /// Return a reverse iterator providing non-modifiable access to the
    /// last character of this view (or the past-the-end reverse iterator if
    /// this view is empty).
    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator  rbegin() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator crbegin() const BSLS_KEYWORD_NOEXCEPT;

    /// Return the past-the-end reverse iterator for this view.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator  rend() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator crend() const BSLS_KEYWORD_NOEXCEPT;

                      // *** capacity ***

    /// Return the length of this view.
    BSLS_KEYWORD_CONSTEXPR
    size_type size() const BSLS_KEYWORD_NOEXCEPT;

    /// Return the length of this view.
    BSLS_KEYWORD_CONSTEXPR
    size_type length() const BSLS_KEYWORD_NOEXCEPT;

    /// Return the maximal possible length of this view.  Note that requests
    /// to create a view longer than this number of characters are
    /// guaranteed to raise an `std::length_error` exception.
    BSLS_KEYWORD_CONSTEXPR
    size_type max_size() const BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if this view has length 0, and `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR
    bool empty() const BSLS_KEYWORD_NOEXCEPT;

                      // *** element access ***

    /// Return a reference providing non-modifiable access to the character
    /// at the specified `position` in this view.  The behavior is undefined
    /// unless `position < length()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_reference operator[](size_type position) const;

    /// Return a reference providing non-modifiable access to the character
    /// at the specified `position` in this view.  Throw `std::out_of_range`
    /// if `position >= length()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_reference at(size_type position) const;

    /// Return a reference providing non-modifiable access to the character
    /// at the first position in this view.  The behavior is undefined if
    /// this view is empty.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_reference front() const;

    /// Return a reference providing non-modifiable access to the character
    /// at the last position in this view.  The behavior is undefined if
    /// this view is empty.  Note that the last position is `length() - 1`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_reference back() const;

    /// Return an address providing non-modifiable access to the underlying
    /// character array.  Note that this array may be not null-terminated.
    BSLS_KEYWORD_CONSTEXPR
    const_pointer data() const BSLS_KEYWORD_NOEXCEPT;

                      // *** string operations ***

    /// Copy from this view, starting from the optionally specified
    /// `position`, the specified `numChars` or `length() - position`
    /// characters, whichever is smaller, into the specified
    /// `characterString` buffer, and return the number of characters
    /// copied.  If `position` is not specified, 0 is used.  Throw
    /// `std::out_of_range` if `position > length()`.  Note that the output
    /// `characterString` is *not* null-terminated.  The behavior is
    /// undefined unless `characterString` has enough room to hold at least
    /// `numChars` or `length() - position`, whichever is smaller, and the
    /// `characterString` does not lie within the source range to be copied.
    size_type copy(CHAR_TYPE *characterString,
                   size_type  numChars,
                   size_type  position = 0) const;

    /// Return a view whose value is the subview starting at the optionally
    /// specified `position` in this view, of length the optionally
    /// specified `numChars` or `length() - position`, whichever is smaller.
    /// If `position` is not specified, 0 is used (i.e., the subview is from
    /// the beginning of this view).  If `numChars` is not specified, `npos`
    /// is used (i.e., the entire suffix from `position` to the end of the
    /// view is returned).  Throw `std::out_of_range` if
    /// `position > length()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view substr(size_type position = 0,
                             size_type numChars = npos) const;

    /// Lexicographically compare this view with the specified `other` view,
    /// and return a negative value if this view is less than `other`, a
    /// positive value if it is greater than `other`, and 0 in case of
    /// equality.  See {Lexicographical Comparisons}.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    int compare(basic_string_view other) const BSLS_KEYWORD_NOEXCEPT;

    /// Lexicographically compare the subview of this view of the specified
    /// `numChars` length starting at the specified `position` (or the
    /// suffix of this view starting at `position` if
    /// `position + numChars > length()`) with the specified `other` view,
    /// and return a negative value if the indicated subview of this view is
    /// less than `other`, a positive value if it is greater than `other`,
    /// and 0 in case of equality.  Throw `std::out_of_range` if
    /// `position > length()`.  See {Lexicographical Comparisons}.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type         position,
                size_type         numChars,
                basic_string_view other) const;

    /// Lexicographically compare the subview of this view of the specified
    /// `lhsNumChars` length starting at the specified `lhsPosition` (or the
    /// suffix of this view starting at `lhsPosition` if
    /// `lhsPosition + lhsNumChars > length()`) with the subview of the
    /// specified `other` view of the specified `otherNumChars` length
    /// starting at the specified `otherPosition` (or the suffix of `other`
    /// starting at `otherPosition` if
    /// `otherPosition + otherNumChars > other.length()`).  Return a
    /// negative value if the indicated subview of this view is less than
    /// the indicated subview of `other`, a positive value if it is greater
    /// than the indicated subview of `other`, and 0 in case of equality.
    /// Throw `std::out_of_range` if `lhsPosition > length()` or
    /// `otherPosition > other.length()`.  See {Lexicographical
    /// Comparisons}.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type         lhsPosition,
                size_type         lhsNumChars,
                basic_string_view other,
                size_type         otherPosition,
                size_type         otherNumChars) const;

    /// Lexicographically compare this view with the specified
    /// null-terminated `other` string (of length
    /// `CHAR_TRAITS::length(other)`), and return a negative value if this
    /// view is less than `other`, a positive value if it is greater than
    /// `other`, and 0 in case of equality.  The behavior is undefined
    /// unless `other` is a null-terminated string.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(const CHAR_TYPE *other) const;

    /// Lexicographically compare the subview of this view of the specified
    /// `lhsNumChars` length starting at the specified `lhsPosition` (or the
    /// suffix of this view starting at `lhsPosition` if
    /// `lhsPosition + lhsNumChars > length()`) with the specified
    /// null-terminated `other` string (of length
    /// `CHAR_TRAITS::length(other)`), and return a negative value if the
    /// indicated subview of this view is less than `other`, a positive
    /// value if it is greater than `other`, and 0 in case of equality.
    /// Throw `std::out_of_range` if `lhsPosition > length()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type        lhsPosition,
                size_type        lhsNumChars,
                const CHAR_TYPE *other) const;

    /// Lexicographically compare the subview of this view of the specified
    /// `lhsNumChars` length starting at the specified `lhsPosition` (or the
    /// suffix of this view starting at `lhsPosition` if
    /// `lhsPosition + lhsNumChars > length()`) with the specified `other`
    /// string of the specified `otherNumChars` length, and return a
    /// negative value if the indicated subview of this view is less than
    /// `other`, a positive value if it is greater than `other`, and 0 in
    /// case of equality.  `CHAR_TRAITS::lt` is used to compare characters.
    /// Throw `std::out_of_range` if `lhsPosition > length()`.  The behavior
    /// is undefined unless `other || 0 == otherNumChars`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type        lhsPosition,
                size_type        lhsNumChars,
                const CHAR_TYPE *other,
                size_type        otherNumChars) const;

    /// Return `true` if this view contains with the specified `subview`, and
    /// `false` otherwise.  See {Lexicographical Comparisons}.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool contains(basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if this view contains with the specified `character`,
    /// and `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR
    bool contains(CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if this view contains with the specified
    /// `characterString`, and `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool contains(const CHAR_TYPE* characterString) const;

    /// Return `true` if this view starts with the specified `subview`, and
    /// `false` otherwise.  See {Lexicographical Comparisons}.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool starts_with(basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if this view starts with the specified `character`,
    /// and `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR
    bool starts_with(CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if this view starts with the specified
    /// `characterString`, and `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool starts_with(const CHAR_TYPE* characterString) const;

    /// Return `true` if this view ends with the specified `subview`, and
    /// `false` otherwise.  See {Lexicographical Comparisons}.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool ends_with(basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT;

    // Return `true` if this view ends with the specified `character`, and
    // `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR
    bool ends_with(CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if this view ends with the specified
    /// `characterString`, and `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool ends_with(const CHAR_TYPE* characterString) const;

    /// Return the starting position of the *first* occurrence of the
    /// specified `subview`, if it can be found in this view (on or *after*
    /// the optionally specified `position`) using `CHAR_TRAITS::eq` to
    /// compare characters, and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find(basic_string_view subview,
                   size_type         position = 0) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the starting position of the *first* occurrence of the
    /// specified `characterString` of the specified `numChars` length, if
    /// such a string can be found in this view (on or *after* the specified
    /// `position`) using `CHAR_TRAITS::eq` to compare characters, and
    /// return `npos` otherwise.  The behavior is undefined unless
    /// `characterString || (numChars == 0)`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find(const CHAR_TYPE *characterString,
                   size_type        position,
                   size_type        numChars) const;

    /// Return the starting position of the *first* occurrence of the
    /// specified null-terminated `characterString`, if such a string can be
    /// found in this view (on or *after* the optionally specified
    /// `position`) using `CHAR_TRAITS::eq` to compare characters, and
    /// return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    size_type find(const CHAR_TYPE *characterString,
                   size_type        position = 0) const;

    /// Return the position of the *first* occurrence of the specified
    /// `character`, if such an occurrence can be found in this view (on or
    /// *after* the optionally specified `position` if such a `position` is
    /// specified), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find(CHAR_TYPE character,
                   size_type position = 0) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the starting position of the *last* occurrence of the
    /// specified `subview` within this view, if such a sequence can be
    /// found in this view (on or *before* the optionally specified
    /// `position` if such a `position` is specified) using
    /// `CHAR_TRAITS::eq` to compare characters, and return `npos`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type rfind(
                basic_string_view subview,
                size_type         position = npos) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the starting position of the *last* occurrence of the
    /// specified `characterString` of the specified `numChars` length, if
    /// such a string can be found in this view (on or *after* the specified
    /// `position`) using `CHAR_TRAITS::eq` to compare characters, and
    /// return `npos` otherwise.  The behavior is undefined unless
    /// `characterString || (numChars == 0)`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type rfind(const CHAR_TYPE *characterString,
                    size_type        position,
                    size_type        numChars) const;

    /// Return the starting position of the *last* occurrence of the
    /// specified null-terminated `characterString`, if such a string can be
    /// found in this view (on or *after* the optionally specified
    /// `position`) using `CHAR_TRAITS::eq` to compare characters, and
    /// return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type rfind(const CHAR_TYPE *characterString,
                    size_type        position = npos) const;

    /// Return the position of the *last* occurrence of the specified
    /// `character`, if such an occurrence can be found in this view (on or
    /// *before* the optionally specified `position` if such a `position` is
    /// specified), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type rfind(CHAR_TYPE character,
                    size_type position = npos) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *first* occurrence of a character
    /// belonging to the specified `subview`, if such an occurrence can be
    /// found in this view (on or *after* the optionally specified
    /// `position` if such a `position` is specified), and return `npos`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_of(
                   basic_string_view subview,
                   size_type         position = 0) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *first* occurrence of a character
    /// belonging to the specified `characterString` of the specified
    /// `numChars` length, if such a string can be found in this view (on or
    /// *after* the specified `position`) using `CHAR_TRAITS::eq` to compare
    /// characters, and return `npos` otherwise.  The behavior is undefined
    /// unless `characterString || (numChars == 0)`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_of(const CHAR_TYPE *characterString,
                            size_type        position,
                            size_type        numChars) const;

    /// Return the position of the *first* occurrence of a character
    /// belonging to the specified `characterString`, if such an occurrence
    /// can be found in this view (on or *after* the optionally specified
    /// `position`), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    size_type find_first_of(const CHAR_TYPE *characterString,
                            size_type        position = 0) const;

    /// Return the position of the *first* occurrence of the specified
    /// `character`, if such an occurrence can be found in this view (on or
    /// *after* the optionally specified `position` if such a `position` is
    /// specified), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_of(
                           CHAR_TYPE character,
                           size_type position = 0) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *last* occurrence of a character
    /// belonging to the specified `subview`, if such an occurrence can be
    /// found in this view (on or *before* the optionally specified
    /// `position` if such a `position` is specified), and return `npos`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_of(
                basic_string_view subview,
                size_type         position = npos) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *last* occurrence of a character
    /// belonging to the specified `characterString` of the specified
    /// `numChars` length, if such a string can be found in this view (on or
    /// *after* the specified `position`) using `CHAR_TRAITS::eq` to compare
    /// characters, and return `npos` otherwise.  The behavior is undefined
    /// unless `characterString || (numChars == 0)`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_of(const CHAR_TYPE *characterString,
                           size_type        position,
                           size_type        numChars) const;

    /// Return the position of the *last* occurrence of a character
    /// belonging to the specified `characterString`, if such an occurrence
    /// can be found in this view (on or *after* the optionally specified
    /// `position`), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    size_type find_last_of(const CHAR_TYPE *characterString,
                           size_type        position = npos) const;

    /// Return the position of the *last* occurrence of the specified
    /// `character`, if such an occurrence can be found in this view (on or
    /// *before* the optionally specified `position` if such a `position` is
    /// specified), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_of(
                        CHAR_TYPE character,
                        size_type position = npos) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *first* occurrence of a character *not*
    /// belonging to the specified `subview`, if such an occurrence can be
    /// found in this view (on or *after* the optionally specified
    /// `position` if such a `position` is specified), and return `npos`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_not_of(
                   basic_string_view subview,
                   size_type         position = 0) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *first* occurrence of a character *not*
    /// belonging to the specified `characterString` of the specified
    /// `numChars` length, if such an occurrence can be found in this view
    /// (on or *after* the specified `position`) using `CHAR_TRAITS::eq` to
    /// compare characters, and return `npos` otherwise.  The behavior is
    /// undefined unless `characterString || (numChars == 0)`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_not_of(const CHAR_TYPE *characterString,
                                size_type        position,
                                size_type        numChars) const;

    /// Return the position of the *first* occurrence of a character *not*
    /// belonging to the specified `characterString`, if such an occurrence
    /// can be found in this view (on or *after* the optionally specified
    /// `position`), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    size_type find_first_not_of(const CHAR_TYPE *characterString,
                                size_type        position = 0) const;

    /// Return the position of the *first* occurrence of a character
    /// *different* from the specified `character`, if such an occurrence
    /// can be found in this view (on or *after* the optionally specified
    /// `position` if such a `position` is specified), and return `npos`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_not_of(
                           CHAR_TYPE character,
                           size_type position = 0) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *last* occurrence of a character *not*
    /// belonging to the specified `subview`, if such an occurrence can be
    /// found in this view (on or *before* the optionally specified
    /// `position` if such a `position` is specified), and return `npos`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_not_of(
                basic_string_view subview,
                size_type         position = npos) const BSLS_KEYWORD_NOEXCEPT;

    /// Return the position of the *last* occurrence of a character *not*
    /// belonging to the specified `characterString` of the specified
    /// `numChars` length, if such an occurrence can be found in this view
    /// (on or *after* the specified `position`) using `CHAR_TRAITS::eq` to
    /// compare characters, and return `npos` otherwise.  The behavior is
    /// undefined unless `characterString || (numChars == 0)`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_not_of(const CHAR_TYPE *characterString,
                               size_type        position,
                               size_type        numChars) const;

    /// Return the position of the *last* occurrence of a character *not*
    /// belonging to the specified `characterString`, if such an occurrence
    /// can be found in this view (on or *after* the optionally specified
    /// `position`), and return `npos` otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP17
    size_type find_last_not_of(const CHAR_TYPE *characterString,
                               size_type        position = npos) const;

    /// Return the position of the *last* occurrence of a character
    /// *different* from the specified `character`, if such an occurrence
    /// can be found in this view (on or *before* the optionally specified
    /// `position` if such a `position` is specified), and return `npos`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_not_of(
                        CHAR_TYPE character,
                        size_type position = npos) const BSLS_KEYWORD_NOEXCEPT;

            // *** BDE compatibility with platform libraries: ***

    /// Convert this `const` object to a string type native to the
    /// compiler`s library, instantiated with the same character type and
    /// traits type.  The return string will contain the same sequence of
    /// characters as this object and will have a default-constructed
    /// allocator.
    template <class ALLOCATOR>
    BSLS_KEYWORD_EXPLICIT
    operator std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>()
    const
    {
        // See {DRQS 131792157} for why this is inline.
        return std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(d_start_p,
                                                                    d_length);
    }
};

// TYPEDEFS
typedef basic_string_view<char>         string_view;
typedef basic_string_view<wchar_t>     wstring_view;

#if defined(BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE)
typedef basic_string_view<char8_t>    u8string_view;
#endif

#if defined(BSLS_COMPILERFEATURES_SUPPORT_UNICODE_CHAR_TYPES)
typedef basic_string_view<char16_t>  u16string_view;
typedef basic_string_view<char32_t>  u32string_view;
#endif

// FREE FUNCTIONS

/// Exchange the value of the specified `a` object with the value of the
/// specified `b` object.
template <class CHAR_TYPE, class CHAR_TRAITS>
void swap(basic_string_view<CHAR_TYPE, CHAR_TRAITS>& a,
          basic_string_view<CHAR_TYPE, CHAR_TRAITS>& b) BSLS_KEYWORD_NOEXCEPT;

}  // close namespace bsl

namespace BloombergLP {
namespace bslstl_stringview_relops {

                    // =============================
                    // struct StringView_CompareUtil
                    // =============================

/// This component-private utility `struct` contains functions for comparing
/// two `string_view` objects.  This functionality is needed to implement
/// the comparison operators operating on string_view objects without
/// resorting to code duplication or delegating directly between different
/// overloads of the same operator.  The need to avoid delegation to
/// overloads stems from a bug in xlC 12 on AIX leading to incorrect
/// overload resolution and infinite recursion.
template <class CHAR_TYPE, class CHAR_TRAITS>
struct StringView_CompareUtil {

    // TYPES
    typedef bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> StringView;

    // CLASS METHODS

    /// Return `true` if `lhs == rhs` and `false` otherwise.
    static
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool equals(StringView lhs, StringView rhs) BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if `lhs < rhs` and `false` otherwise.
    static
    BSLS_KEYWORD_CONSTEXPR_CPP17
    bool lessThan(StringView lhs, StringView rhs) BSLS_KEYWORD_NOEXCEPT;
};

// FREE OPERATORS

/// Return `true` if the specified `lhs` view has the same value as the
/// specified `rhs` view, and `false` otherwise.  Two views have the same
/// value if they have the same length, and the characters at each
/// respective position have the same value according to `CHAR_TRAITS::eq`.
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator==(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator==(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator==(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` view has a different value from the
/// specified `rhs` view, and `false` otherwise.  Two views have the same
/// value if they have the same length, and the characters at each
/// respective position have the same value according to `CHAR_TRAITS::eq`.
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator!=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator!=(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator!=(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` view has a lexicographically
/// smaller value than the specified `rhs` view, and `false` otherwise.  See
/// {Lexicographical Comparisons}.
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator<(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
               bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator<(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator<(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` view has a lexicographically larger
/// value than the specified `rhs` view, and `false` otherwise.  See
/// {Lexicographical Comparisons}.
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator>(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
               bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator>(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator>(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` view has a value lexicographically
/// smaller than or or equal to the specified `rhs` view, and `false`
/// otherwise.  See {Lexicographical Comparisons}.
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator<=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator<=(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator<=(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` view has a value lexicographically
/// larger than or equal to the specified `rhs` view, and `false` otherwise.
/// See {Lexicographical Comparisons}.
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator>=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator>=(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
bool operator>=(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;

}  // close namespace bslstl_stringview_relops
}  // close enterprise namespace

namespace bsl {

/// Write the value of the string bound to the specified `stringView` to the
/// specified output `stream` and return a reference to the modifiable
/// `stream`.
template <class CHAR_TYPE, class CHAR_TRAITS>
std::basic_ostream<CHAR_TYPE>&
operator<<(std::basic_ostream<CHAR_TYPE>&            stream,
           basic_string_view<CHAR_TYPE, CHAR_TRAITS> stringView);

// HASH SPECIALIZATIONS

/// Pass the specified `input` string to the specified `hashAlg` hashing
/// algorithm of the (template parameter) type `HASHALG`.
template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS>
void hashAppend(HASHALG&                                         hashAlg,
                const basic_string_view<CHAR_TYPE, CHAR_TRAITS>& input);

/// Specialize `bsl::hash` for strings, including an overload for pointers
/// to allow character arrays to be hashed without converting them first.
template <class CHAR_TYPE, class CHAR_TRAITS>
struct hash<basic_string_view<CHAR_TYPE, CHAR_TRAITS> >
    : ::BloombergLP::bslh::Hash<>
{
    // PUBLIC ACCESSORS

    /// Compute and return the hash value of the specified `input`.
    std::size_t operator()(
                 const basic_string_view<CHAR_TYPE, CHAR_TRAITS>& input) const;

    /// Compute and return the hash value of the contents of the specified
    /// null-terminated `input`.  This value will be the same as the hash
    /// value of a `basic_string_view` constructed from `input`.
    std::size_t operator()(const CHAR_TYPE *input) const;
};

#if defined(BSLS_PLATFORM_CMP_SUN)  // {DRQS 132030795}

// Sun CC 12.3 has trouble with the partial specializations above in certain
// circumstances (see {DRQS 132030795}).  Adding these explicit specializations
// for `string_view` and `wstring_view` makes the problematic cases work.

template <>
struct hash<string_view> : ::BloombergLP::bslh::Hash<>
{
    // PUBLIC ACCESSORS

    /// Compute and return the hash value of the specified `input`.
    std::size_t operator()(const string_view& input) const;

    /// Compute and return the hash value of the contents of the specified
    /// null-terminated `input`.  This value will be the same as the hash
    /// value of a `basic_string_view` constructed from `input`.
    std::size_t operator()(const char *input) const;
};

template <>
struct hash<wstring_view> : ::BloombergLP::bslh::Hash<>
{
    // PUBLIC ACCESSORS

    /// Compute and return the hash value of the specified `input`.
    std::size_t operator()(const wstring_view& input) const;

    /// Compute and return the hash value of the contents of the specified
    /// null-terminated `input`.  This value will be the same as the hash
    /// value of a `basic_string_view` constructed from `input`.
    std::size_t operator()(const wchar_t *input) const;
};

#endif  // defined(BSLS_PLATFORM_CMP_SUN)

}  // close namespace bsl

#endif  // BSLSTL_STRING_VIEW_IS_ALIASED

#if defined (BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY) && \
    defined (BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)
namespace bsl {
inline namespace literals {
inline namespace string_view_literals {

// FREE OPERATORS

/// Convert a character sequence of the specified `length` excluding the
/// terminating null character starting at the beginning of the specified
/// `characterString` to a string_view object of the indicated return type.
/// (See the "User-Defined Literals" section in the component-level
/// documentation.)
///
/// Example:
/// ```
///    using namespace bsl::string_view_literals;
///    bsl::string_view sv1 = "123\0abc";
///    bsl::string_view sv2 = "123\0abc"_sv;
///    assert(3 == sv1.size());
///    assert(7 == sv2.size());
///
///    bsl::wstring_view sv3 = L"123\0abc"_sv;
///    assert(7 == sv3.size());
/// ```
 string_view operator ""_sv(const char    *characterString,
                            std::size_t    length);
wstring_view operator ""_sv(const wchar_t *characterString,
                            std::size_t    length);

}  // close namespace string_view_literals
}  // close namespace literals
}  // close namespace bsl
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY &&
        // BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE

#ifdef BSLSTL_STRING_VIEW_IS_ALIASED
namespace BloombergLP {
namespace bslh {

/// Pass the specified `input` string to the specified `hashAlg` hashing
/// algorithm of the (template parameter) type `HASHALG`.  Note that this
/// function violates the BDE coding standard, adding a function for a
/// namespace for a different package, and none of the function parameters
/// are from this package either.  This is necessary in order to provide an
/// implementation of `bslh::hashAppend` for the (native) standard library
/// `string_view` type as we are not allowed to add overloads directly into
/// namespace `std`, and this component essentially provides the interface
/// between `bsl` and `std` string types.
template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void hashAppend(HASHALG&                                              hashAlg,
                const std::basic_string_view<CHAR_TYPE, CHAR_TRAITS>& input);

}  // close namespace bslh
}  // close enterprise namespace
#endif  // BSLSTL_STRING_VIEW_IS_ALIASED

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================

#ifndef BSLSTL_STRING_VIEW_IS_ALIASED

#if BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER

namespace BloombergLP {
namespace bslstl {

template <class TYPE>
template <class ARG_TYPE>
inline
StringView_Identity<TYPE>::type::type(
            const ARG_TYPE& argument,
            typename bsl::enable_if<bsl::is_convertible<ARG_TYPE, TYPE>::value,
                                    int>::type)
: d_value(argument)
{}

// MANIPULATORS
template <class TYPE>
inline
TYPE& StringView_Identity<TYPE>::type::operator=(const TYPE& rhs)
{
    d_value = rhs;

    return d_value;
}

template <class TYPE>
inline
StringView_Identity<TYPE>::type::operator TYPE&()
{
    return d_value;
}

// ACCESSOR
template <class TYPE>
inline
StringView_Identity<TYPE>::type::operator const TYPE&() const
{
    return d_value;
}

}  // close package namespace
}  // close enterprise namespace

#endif

namespace bsl {

                          // -----------------------
                          // class basic_string_view
                          // -----------------------

// CLASS DATA
template <class CHAR_TYPE, class CHAR_TRAITS>
const typename basic_string_view<CHAR_TYPE,CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE,CHAR_TRAITS>::npos;

// PRIVATE ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP17
int basic_string_view<CHAR_TYPE,CHAR_TRAITS>::privateCompareRaw(
                                          size_type        lhsPosition,
                                          size_type        lhsNumChars,
                                          const CHAR_TYPE *other,
                                          size_type        otherNumChars) const
{
    BSLS_ASSERT_SAFE(lhsPosition <= length());

    size_type numChars  = lhsNumChars < otherNumChars ? lhsNumChars
                                                      : otherNumChars;
    int       cmpResult = CHAR_TRAITS::compare(data() + lhsPosition,
                                               other,
                                               numChars);
    if (cmpResult) {
        return cmpResult;                                             // RETURN
    }
    if (lhsNumChars < otherNumChars) {
        return -1;                                                    // RETURN
    }
    if (lhsNumChars > otherNumChars) {
        return 1;                                                     // RETURN
    }
    return 0;
}

// CREATORS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
basic_string_view<CHAR_TYPE,CHAR_TRAITS>::basic_string_view()
                                                          BSLS_KEYWORD_NOEXCEPT
: d_start_p(0)
, d_length(0)
{}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
                                              const CHAR_TYPE *characterString)
: d_start_p(characterString)
, d_length(characterString ? CHAR_TRAITS::length(characterString) : 0)
{
    BSLS_ASSERT_SAFE(characterString);
    BSLS_ASSERT_SAFE(d_length <= max_size());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
                                             const CHAR_TYPE  *characterString,
                                             size_type         numChars)
: d_start_p(characterString)
, d_length(numChars)
{
    BSLS_ASSERT_SAFE(characterString || (numChars == 0));
    BSLS_ASSERT_SAFE(numChars <= max_size());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
template <class CONTG_ITER,  class SENTINEL>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
                      CONTG_ITER first,
                      SENTINEL   last,
                      typename
                      bsl::enable_if<
                      BasicStringView_IsCompatibleIterator<CHAR_TYPE,
                                                           CONTG_ITER>::value
                   && BasicStringView_IsCompatibleSentinel<SENTINEL  >::value
                      >::type *)
: d_start_p(first)
, d_length(last - first)
{
    BSLS_ASSERT_SAFE(first || last - first == 0);
    BSLS_ASSERT_SAFE(         last - first >= 0);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
template <class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
               const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& str)
: d_start_p(str.data())
, d_length(str.size())
{
}

#ifdef BSLSTL_STRING_VIEW_AND_STD_STRING_VIEW_COEXIST
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
                    const std::basic_string_view<CHAR_TYPE, CHAR_TRAITS>& view)
: d_start_p(view.data())
, d_length (view.size())
{
}
#endif // BSLSTL_STRING_VIEW_AND_STD_STRING_VIEW_COEXIST

// MANIPULATORS
template <class CHAR_TYPE, class CHAR_TRAITS>
template <class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>&
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::operator=(
               const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& rhs)
BSLS_KEYWORD_NOEXCEPT
{
    d_start_p = rhs.data();
    d_length  = rhs.size();
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP14
void
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::remove_prefix(size_type numChars)
{
    BSLS_ASSERT_SAFE(d_length >= numChars);
    d_start_p += numChars;
    d_length  -= numChars;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP14
void
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::remove_suffix(size_type numChars)
{
    BSLS_ASSERT_SAFE(d_length >= numChars);
    d_length -= numChars;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
void
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::swap(
                                basic_string_view& other) BSLS_KEYWORD_NOEXCEPT
{
    BloombergLP::bslalg::ScalarPrimitives::swap(d_length,  other.d_length);
    BloombergLP::bslalg::ScalarPrimitives::swap(d_start_p, other.d_start_p);
}

// ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::begin() const BSLS_KEYWORD_NOEXCEPT
{
    return d_start_p;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::cbegin() const BSLS_KEYWORD_NOEXCEPT
{
    return begin();
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::end() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return begin() + d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::cend() const BSLS_KEYWORD_NOEXCEPT
{
    return end();
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reverse_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rbegin() const BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(end());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reverse_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::crbegin() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(end());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reverse_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rend() const BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(begin());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reverse_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::crend() const BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(begin());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size() const BSLS_KEYWORD_NOEXCEPT
{
    return d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::length() const BSLS_KEYWORD_NOEXCEPT
{
    return d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::max_size() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return (npos - 1) / sizeof(CHAR_TYPE);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::empty() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return (0 == d_length);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reference
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::operator[](size_type position) const
{
    BSLS_ASSERT_SAFE(position < length());

    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reference
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::at(size_type position) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position >= length())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                                       "string_view::at(n): invalid position");
    }
    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reference
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::front() const
{
    BSLS_ASSERT_SAFE(!empty());

    return *begin();
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reference
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::back() const
{
    BSLS_ASSERT_SAFE(!empty());

    return *(end() - 1);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_pointer
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::data() const BSLS_KEYWORD_NOEXCEPT
{
    return d_start_p;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::copy(CHAR_TYPE *characterString,
                                                size_type  numChars,
                                                size_type  position) const
{

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position > length())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                             "string_view::copy(str,pos,n): invalid position");
    }

    BSLS_ASSERT_SAFE(characterString);

    if (numChars > length() - position) {
        numChars = length() - position;
    }

    // Check that the destination buffer start is not within the source.
    BSLS_ASSERT_SAFE(std::less<const CHAR_TYPE *>()(
                         characterString, d_start_p + position) ||
                     std::greater_equal<const CHAR_TYPE *>()(
                         characterString, d_start_p + position + numChars));

    CHAR_TRAITS::move(characterString, d_start_p + position, numChars);

    return numChars;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::substr(size_type position,
                                                  size_type numChars) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position > length())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                               "string_view::substr(pos,n): invalid position");
    }

    const size_type maxLen = length() - position;

    return basic_string_view<CHAR_TYPE, CHAR_TRAITS>(
                                        data() + position,
                                        numChars < maxLen ? numChars : maxLen);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                           basic_string_view other) const BSLS_KEYWORD_NOEXCEPT
{
    return privateCompareRaw(size_type(0),
                             length(),
                             other.data(),
                             other.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                                 size_type         position,
                                                 size_type         numChars,
                                                 basic_string_view other) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < position)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
            "const string_view<...>::compare(pos,n, other): invalid position");
    }

    if (numChars > length() - position) {
        numChars = length() - position;
    }
    return privateCompareRaw(position, numChars, other.data(), other.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                         size_type         lhsPosition,
                                         size_type         lhsNumChars,
                                         basic_string_view other,
                                         size_type         otherPosition,
                                         size_type         otherNumChars) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < lhsPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
               "const string_view<...>::compare(pos,n,other,other_pos,other_n)"
               ": invalid lhs position");
    }

    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                             other.length() < otherPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
               "const string_view<...>::compare(pos,n,other,other_pos,other_n)"
               ": invalid rhs position");
    }

    if (otherNumChars > other.length() - otherPosition) {
        otherNumChars = other.length() - otherPosition;
    }
    return privateCompareRaw(lhsPosition,
                             lhsNumChars,
                             other.data() + otherPosition,
                             otherNumChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                                  const CHAR_TYPE *other) const
{
    BSLS_ASSERT_SAFE(other);

    size_type otherLength = CHAR_TRAITS::length(other);

    return privateCompareRaw(size_type(0),
                             length(),
                             other,
                             otherLength);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                                  size_type        lhsPosition,
                                                  size_type        lhsNumChars,
                                                  const CHAR_TYPE *other) const
{
    BSLS_ASSERT_SAFE(other);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < lhsPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
             "const string_view<...>::compare(pos,n,other): invalid position");
    }

    size_type otherLength = CHAR_TRAITS::length(other);

    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }

    return compare(lhsPosition,
                   lhsNumChars,
                   other,
                   otherLength);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                          size_type        lhsPosition,
                                          size_type        lhsNumChars,
                                          const CHAR_TYPE *other,
                                          size_type        otherNumChars) const
{
    BSLS_ASSERT_SAFE(other || 0 == otherNumChars);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < lhsPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                       "const string_view<...>::compare(pos,n,other,other_pos)"
                      ": invalid position");
    }

    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }
    return privateCompareRaw(lhsPosition,
                             lhsNumChars,
                             other,
                             otherNumChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::contains(
                         basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT
{
    return npos != find(subview);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::contains(
                               CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT
{
    return npos != find(character);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::contains(
                                        const CHAR_TYPE* characterString) const
{
    BSLS_ASSERT_SAFE(characterString);
    return npos != find(characterString);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::starts_with(
                         basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT
{
    return (size() >= subview.size() &&
            0 == compare(0, subview.size(), subview));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::starts_with(
                               CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT
{
    return (!empty() && CHAR_TRAITS::eq(front(), character));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::starts_with(
                                        const CHAR_TYPE* characterString) const
{
    BSLS_ASSERT_SAFE(characterString);
    for (size_type i = 0; i < d_length; ++i) {
        if (characterString[i] == 0) {
            // Ran out of characterString, so is prefix.
            return true;                                              // RETURN
        }
        if (d_start_p[i] != characterString[i]) {
            // Mismatch.
            return false;                                             // RETURN
        }
    }
    // Ran out of string_view, so check characterString is not longer.
    return characterString[d_length] == 0;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::ends_with(
                         basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT
{
    return (size() >= subview.size() &&
            0 == compare(size() - subview.size(), npos, subview));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::ends_with(
                               CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT
{
    return (!empty() && CHAR_TRAITS::eq(back(), character));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::ends_with(
                                        const CHAR_TYPE* characterString) const
{
    return ends_with(basic_string_view(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
 BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                                               const CHAR_TYPE *substring,
                                               size_type        position,
                                               size_type        numChars) const
{
    BSLS_ASSERT_SAFE(substring || (numChars == 0));

    size_type remChars = length() - position;
    if (position > length() || numChars > remChars) {
        return npos;                                                  // RETURN
    }
    if (0 == numChars) {
        return position;                                              // RETURN
    }
    const CHAR_TYPE *thisString = data() + position;
    const CHAR_TYPE *nextString = 0;
    for (remChars -= numChars - 1;
         0 !=
            (nextString = CHAR_TRAITS::find(thisString, remChars, *substring));
         remChars -= ++nextString - thisString, thisString = nextString) {
        if (0 == CHAR_TRAITS::compare(nextString, substring, numChars)) {
            return nextString - data();                               // RETURN
        }
    }

    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find(characterString,
                position,
                CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    if (position >= length()) {
        return npos;                                                  // RETURN
    }
    const CHAR_TYPE *result = CHAR_TRAITS::find(data() + position,
                                                length() - position,
                                                character);
    return result ? result - data() : npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rfind(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return rfind(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rfind(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 == numChars) {
        return position > length() ? length() : position;             // RETURN
    }
    if (numChars <= length()) {
        if (position > length() - numChars) {
            position = length() - numChars;
        }
        const CHAR_TYPE *thisString = data() + position;
        for (; position != npos; --thisString, --position) {
            if (0 == CHAR_TRAITS::compare(thisString,
                                          characterString,
                                          numChars)) {
                return position;                                      // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rfind(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return rfind(characterString,
                 position,
                 CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rfind(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    return rfind(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_first_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_first_of(characterString,
                         position,
                         CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 < numChars && position < length()) {
        for (const CHAR_TYPE *current = data() + position;
             current != end();
             ++current)
        {
            if (CHAR_TRAITS::find(characterString, numChars, *current) != 0) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_of(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_first_of(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_last_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_last_of(characterString,
                        position,
                        CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 < numChars && 0 < length()) {
        size_type remChars = position < length() ? position : length() - 1;
        for (const CHAR_TYPE *current = data() + remChars;
             current >= data();
             --current)
        {
            if (CHAR_TRAITS::find(characterString, numChars, *current)) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_of(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_last_of(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
 BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_not_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_first_not_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_not_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_first_not_of(characterString,
                             position,
                             CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_not_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (position < length()) {
        for (const CHAR_TYPE *current = data() + position;
             current != end();
             ++current)
        {
            if (!CHAR_TRAITS::find(characterString, numChars, *current)) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_not_of(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_first_not_of(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_not_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_last_not_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP17
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_not_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_last_not_of(characterString,
                            position,
                            CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_not_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 < length()) {
        size_type remChars = position < length() ? position : length() - 1;
        for (const CHAR_TYPE *current = data() + remChars;
             current >= data();
             --current)
        {
            if (!CHAR_TRAITS::find(characterString, numChars, *current)) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_not_of(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_last_not_of(&character, position, size_type(1));
}

// PUBLIC ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
std::size_t hash<basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::
operator()(const basic_string_view<CHAR_TYPE, CHAR_TRAITS>& input) const
{
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input.data(), sizeof(CHAR_TYPE) * input.size());
    hashAppend(hashAlg, input.size());
    return static_cast<std::size_t>(hashAlg.computeHash());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
std::size_t hash<basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::
operator()(const CHAR_TYPE *input) const
{
    BSLS_ASSERT_SAFE(input);
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;

    std::size_t length = CHAR_TRAITS::length(input);

    hashAlg(input, sizeof(CHAR_TYPE) * length);
    hashAppend(hashAlg, length);
    return static_cast<std::size_t>(hashAlg.computeHash());
}

#if defined(BSLS_PLATFORM_CMP_SUN)  // {DRQS 132030795}

inline
std::size_t hash<string_view>::operator()(const string_view& input) const
{
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input.data(), input.size());
    hashAppend(hashAlg, input.size());
    return static_cast<std::size_t>(hashAlg.computeHash());
}

inline
std::size_t hash<string_view>::operator()(const char *input) const
{
    BSLS_ASSERT_SAFE(input);
    using ::BloombergLP::bslh::hashAppend;
    std::size_t length = char_traits<char>::length(input);
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input, length);
    hashAppend(hashAlg, length);
    return static_cast<std::size_t>(hashAlg.computeHash());
}

inline
std::size_t hash<wstring_view>::operator()(const wstring_view& input) const
{
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input.data(), sizeof(wchar_t) * input.size());
    hashAppend(hashAlg, input.size());
    return static_cast<std::size_t>(hashAlg.computeHash());
}

inline
std::size_t hash<wstring_view>::operator()(const wchar_t *input) const
{
    BSLS_ASSERT_SAFE(input);
    using ::BloombergLP::bslh::hashAppend;
    std::size_t length = char_traits<wchar_t>::length(input);
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input, sizeof(wchar_t) * length);
    hashAppend(hashAlg, length);
    return static_cast<std::size_t>(hashAlg.computeHash());
}

#endif

}  // close namespace bsl

namespace BloombergLP {
namespace bslstl_stringview_relops {

                            // ----------------------
                            // StringView_CompareUtil
                            // ----------------------

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(
                          StringView lhs, StringView rhs) BSLS_KEYWORD_NOEXCEPT
{
    return lhs.size() == rhs.size()
        && 0 == CHAR_TRAITS::compare(lhs.data(), rhs.data(), lhs.size());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(
                          StringView lhs, StringView rhs) BSLS_KEYWORD_NOEXCEPT
{
    const std::size_t minLen = lhs.length() < rhs.length()
                             ? lhs.length() : rhs.length();

    int ret = CHAR_TRAITS::compare(lhs.data(), rhs.data(), minLen);
    if (0 == ret) {
        return lhs.length() < rhs.length();                           // RETURN
    }
    return (ret < 0);
}

}  // close namespace bslstl_stringview_relops
}  // close enterprise namespace

// FREE FUNCTIONS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
void bsl::swap(
            basic_string_view<CHAR_TYPE, CHAR_TRAITS>& a,
            basic_string_view<CHAR_TYPE, CHAR_TRAITS>& b) BSLS_KEYWORD_NOEXCEPT
{
    a.swap(b);
}

// FREE OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator==(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>        lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>        rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator==(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator==(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator!=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator!=(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator!=(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator<(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
          bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator<(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
          const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator<(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
          typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator>(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
          bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator>(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
          const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator>(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
          typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator<=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator<=(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator<=(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator>=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator>=(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP17
bool BloombergLP::bslstl_stringview_relops::
operator>=(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

namespace bsl {

using BloombergLP::bslstl_stringview_relops::operator==;
using BloombergLP::bslstl_stringview_relops::operator!=;
using BloombergLP::bslstl_stringview_relops::operator<;
using BloombergLP::bslstl_stringview_relops::operator>;
using BloombergLP::bslstl_stringview_relops::operator<=;
using BloombergLP::bslstl_stringview_relops::operator>=;

}  // close namespace bsl

template <class CHAR_TYPE, class CHAR_TRAITS>
std::basic_ostream<CHAR_TYPE>&
bsl::operator<<(std::basic_ostream<CHAR_TYPE>&            stream,
                basic_string_view<CHAR_TYPE, CHAR_TRAITS> stringView)
{
    typedef CHAR_TYPE                                           char_type;
    typedef typename std::basic_ostream<char_type>::ios_base    ios_base;
    typedef typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
                                                                size_type;

    size_type width = static_cast<size_type>(stream.width());
    size_type len = stringView.length();

    if (len < width) {
        bool leftAdjusted =
                    (stream.flags() & ios_base::adjustfield) == ios_base::left;

        char_type fillChar = stream.fill();

        if (leftAdjusted) {
            if (stringView.data()) {
                 stream.write(stringView.data(), stringView.length());
            }
        }

        for (size_type n = 0; n != width - len; ++n) {
            stream.put(fillChar);
        }

        if (!leftAdjusted) {
            if (stringView.data()) {
                 stream.write(stringView.data(), stringView.length());
            }
        }
    }
    else {
        if (stringView.data()) {
            stream.write(stringView.data(), stringView.length());
        }
    }

    stream.width(0);

    return stream;
}

// HASH SPECIALIZATIONS
template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS>
inline
void bsl::hashAppend(HASHALG&                                         hashAlg,
                     const basic_string_view<CHAR_TYPE, CHAR_TRAITS>& input)
{
    using ::BloombergLP::bslh::hashAppend;
    hashAlg(input.data(), sizeof(CHAR_TYPE)*input.size());
    hashAppend(hashAlg, input.size());
}

#endif  // BSLSTL_STRING_VIEW_IS_ALIASED

#ifdef BSLSTL_STRING_VIEW_IS_ALIASED
namespace BloombergLP {

template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void bslh::hashAppend(
                 HASHALG&                                              hashAlg,
                 const std::basic_string_view<CHAR_TYPE, CHAR_TRAITS>& input)
{
    hashAlg(input.data(), sizeof(CHAR_TYPE)*input.size());
    hashAppend(hashAlg, input.size());
}

}  // close enterprise namespace
#endif  // BSLSTL_STRING_VIEW_IS_ALIASED

#undef BSLSTL_STRING_VIEW_AND_STD_STRING_VIEW_COEXIST

#endif

// ----------------------------------------------------------------------------
// Copyright 2019 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
